import java.io.*;

public class DynamicClassOverloader extends ClassLoader {

  private java.util.Map classesHash= new java.util.HashMap();

  public final String[] classPath;

  public DynamicClassOverloader(String[] classPath) {

      this.classPath= classPath;

  }
  
	
  private boolean compile( String javaFile ) throws IOException {
	
	System.out.println( "Compiling "+javaFile+"..." );
	
	Process p = Runtime.getRuntime().exec( "javac "+javaFile );
	
	try {
		p.waitFor();
	} catch( InterruptedException ie ) { System.out.println( ie ); }
	
	int ret = p.exitValue();
	
	return ret==0;
  }

  protected synchronized Class loadClass(String name,boolean resolve)

    throws ClassNotFoundException

  {

    String fileStub = name.replace( '.', '/' );
	String javaFilename = fileStub+".java";
	String classFilename = fileStub+".class";
	File javaFile = new File( javaFilename );
	File classFile = new File( classFilename );
	
	if (javaFile.exists() && javaFile.lastModified() > classFile.lastModified()) {
		try {
		
		if (!compile( javaFilename ) || !classFile.exists()) {
			throw new ClassNotFoundException( "Compile failed: "+javaFilename );
		}
	} catch( IOException ie ) {
		
		throw new ClassNotFoundException( ie.toString() );
		}
	}
	
	Class result= findClass(name);

    if (resolve) resolveClass(result);

    return result;
  }

  protected Class findClass(String name)

    throws ClassNotFoundException

  {

    Class result= (Class)classesHash.get(name);

    if (result!=null) {

      

      System.out.println("% Class "+name+" found in cache");

      

      return result;

    }

    File f= findFile(name.replace('.','/'),".class");

    System.out.println("% Class "+name+(f==null?"":" found in "+f));

    if (f==null) {

		return findSystemClass(name);
    }

    try {

      byte[] classBytes= loadFileAsBytes(f);

      result= defineClass(name,classBytes,0,classBytes.length);

    } catch (IOException e) {

      throw new ClassNotFoundException("Cannot load class "+name+": "+e);

    } catch (ClassFormatError e) {

      throw new ClassNotFoundException("Format of class file incorrect for class "+name+": "+e);

    }

    classesHash.put(name,result);

    return result;

  }

  protected java.net.URL findResource(String name) {

    File f= findFile(name,"");

    if (f==null) return null;

    try {

      return f.toURL();

    } catch(java.net.MalformedURLException e) {

      return null;

    }

  }

  private File findFile(String name, String extension) {

    for (int k=0; k<classPath.length; k++) {

     File f= new File((new File(classPath[k])).getPath()+File.separatorChar+name.replace('/',File.separatorChar)+extension);

      if (f.exists()) return f;

    }

    return null;

  }

  public static byte[] loadFileAsBytes(File file)

    throws IOException

  {

    byte[] result= new byte[(int)file.length()];

    FileInputStream f= new FileInputStream(file);

    try {

      f.read(result,0,result.length);

    } finally {

      try {

        f.close();

      } catch (Exception e) {       

      };
    }

    return result;

  }
 }